import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import subprocess
import sys
import os
import configparser
import cv2

class VideoAppLauncher:
    def __init__(self, root):
        self.root = root
        self.root.title("灵眸测谎动态感知——摄像头智能测谎软件 v1.0 powered by xiaoke")
        self.root.geometry("560x480")
        self.root.resizable(True, True)
        
        # 尝试设置图标，如果文件不存在则忽略
        try:
            self.root.iconbitmap('ico.ico')
        except:
            pass
        
        # 配置文件路径
        self.config_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.ini")
        
        # 存储当前运行的进程
        self.current_process = None
        
        # 设置中文字体支持
        self.style = ttk.Style()
        self.style.configure("TLabel", font=("SimHei", 12))
        self.style.configure("TButton", font=("SimHei", 12))
        self.style.configure("TRadiobutton", font=("SimHei", 12))
        self.style.configure("TCheckbutton", font=("SimHei", 12))
        
        self.create_widgets()
        
        # 自动加载配置
        self.load_config()
        
        # 注册窗口关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        
    def create_widgets(self):
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="20")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 输入源选择
        ttk.Label(main_frame, text="输入源选择:").grid(row=0, column=0, sticky=tk.W, pady=5)
        
        input_frame = ttk.LabelFrame(main_frame, text="输入设置", padding="10")
        input_frame.grid(row=1, column=0, sticky=(tk.W, tk.E), pady=5)
        
        # 输入类型选择
        self.input_type = tk.StringVar(value="device")
        
        ttk.Radiobutton(input_frame, text="视频设备", variable=self.input_type, value="device").grid(row=0, column=0, sticky=tk.W, pady=2)
        ttk.Radiobutton(input_frame, text="文件", variable=self.input_type, value="file").grid(row=0, column=1, sticky=tk.W, pady=2)
        ttk.Radiobutton(input_frame, text="屏幕区域", variable=self.input_type, value="screen").grid(row=0, column=2, sticky=tk.W, pady=2)
        
        # 输入设备序号
        input_row_frame = ttk.Frame(input_frame)
        input_row_frame.grid(row=1, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=5)
        
        ttk.Label(input_row_frame, text="摄像头序号").grid(row=0, column=0, sticky=tk.W, pady=5)
        self.input_device = ttk.Entry(input_row_frame, width=10)
        self.input_device.grid(row=0, column=1, sticky=(tk.W, tk.E), pady=5, padx=5)
        self.input_device.insert(0, "0")
        
        # 摄像头检测按钮
        self.detect_btn = ttk.Button(input_row_frame, text="检测摄像头", command=self.detect_cameras)
        self.detect_btn.grid(row=0, column=2, sticky=tk.W, pady=5, padx=5)
        
        # 文件选择按钮
        self.file_path_label = ttk.Label(input_row_frame, text="视频文件路径")
        self.file_path_label.grid(row=1, column=0, sticky=tk.W, pady=5)
        self.file_path_entry = ttk.Entry(input_row_frame, width=30)
        self.file_path_entry.grid(row=1, column=1, columnspan=2, sticky=(tk.W, tk.E), pady=5, padx=5)
        
        self.file_select_btn = ttk.Button(input_row_frame, text="选择文件", command=self.select_file)
        self.file_select_btn.grid(row=1, column=3, sticky=tk.W, pady=5, padx=5)
        
        # 屏幕区域输入
        screen_frame = ttk.Frame(input_frame)
        screen_frame.grid(row=2, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=5)
        
        ttk.Label(screen_frame, text="屏幕区域 (x y 宽度 高度):").grid(row=0, column=0, sticky=tk.W)
        self.screen_x = ttk.Entry(screen_frame, width=8)
        self.screen_y = ttk.Entry(screen_frame, width=8)
        self.screen_width = ttk.Entry(screen_frame, width=8)
        self.screen_height = ttk.Entry(screen_frame, width=8)
        
        self.screen_x.grid(row=0, column=1, padx=2)
        self.screen_y.grid(row=0, column=2, padx=2)
        self.screen_width.grid(row=0, column=3, padx=2)
        self.screen_height.grid(row=0, column=4, padx=2)
        
        # 选项设置
        options_frame = ttk.LabelFrame(main_frame, text="功能选项", padding="10")
        options_frame.grid(row=2, column=0, sticky=(tk.W, tk.E), pady=10)
        
        self.draw_landmarks = tk.BooleanVar()
        self.draw_bpm = tk.BooleanVar()
        self.flip_output = tk.BooleanVar()
        self.record_output = tk.BooleanVar()
        
        ttk.Checkbutton(options_frame, text="显示面部和手部关键点", variable=self.draw_landmarks).grid(row=0, column=0, sticky=tk.W, pady=2)
        ttk.Checkbutton(options_frame, text="录制视频", variable=self.record_output).grid(row=0, column=1, sticky=tk.W, pady=2)
        
        # TTL设置
        ttk.Label(options_frame, text="显示持续帧数:").grid(row=2, column=0, sticky=tk.W, pady=5)
        self.ttl_value = ttk.Entry(options_frame, width=10)
        self.ttl_value.grid(row=2, column=1, sticky=tk.W, pady=5)
        self.ttl_value.insert(0, "30")
        
        # 次要视频设备
        ttk.Label(options_frame, text="次要视频设备:").grid(row=3, column=0, sticky=tk.W, pady=5)
        self.secondary_device = ttk.Entry(options_frame, width=30)
        self.secondary_device.grid(row=3, column=1, sticky=tk.W, pady=5)
        
        # 按钮区域
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=3, column=0, sticky=(tk.W, tk.E), pady=10)
        
        # 配置按钮框架的列权重，使第二列扩展
        button_frame.columnconfigure(1, weight=1)

        # 将按钮放在第二列并右对齐
        ttk.Button(button_frame, text="启动应用", command=self.launch_app_with_save).grid(row=0, column=1, sticky=tk.E, padx=5)
        ttk.Button(button_frame, text="退出", command=self.on_closing).grid(row=0, column=2, sticky=tk.E, padx=5)
        
        # 状态区域
        self.status_var = tk.StringVar(value="就绪")
        ttk.Label(main_frame, textvariable=self.status_var).grid(row=4, column=0, sticky=tk.W, pady=5)
        
        # 根据输入类型切换可见性
        self.input_type.trace_add("write", self.update_input_visibility)
        self.update_input_visibility()
    
    def update_input_visibility(self, *args):
        if self.input_type.get() == "screen":
            self.input_device.config(state=tk.DISABLED)
            self.detect_btn.config(state=tk.DISABLED)
            self.file_path_entry.config(state=tk.DISABLED)
            self.screen_x.config(state=tk.NORMAL)
            self.screen_y.config(state=tk.NORMAL)
            self.screen_width.config(state=tk.NORMAL)
            self.screen_height.config(state=tk.NORMAL)
        elif self.input_type.get() == "device":
            self.input_device.config(state=tk.NORMAL)
            self.detect_btn.config(state=tk.NORMAL)
            self.file_path_entry.config(state=tk.DISABLED)
            self.screen_x.config(state=tk.DISABLED)
            self.screen_y.config(state=tk.DISABLED)
            self.screen_width.config(state=tk.DISABLED)
            self.screen_height.config(state=tk.DISABLED)
        elif self.input_type.get() == "file":
            self.input_device.config(state=tk.NORMAL)
            self.detect_btn.config(state=tk.DISABLED)
            self.file_path_entry.config(state=tk.NORMAL)
            self.screen_x.config(state=tk.DISABLED)
            self.screen_y.config(state=tk.DISABLED)
            self.screen_width.config(state=tk.DISABLED)
            self.screen_height.config(state=tk.DISABLED)
    
    def detect_cameras(self):
        """检测系统中可用的摄像头设备"""
        available_cameras = []
        max_tries = 10  # 尝试检测最多10个设备
        
        for i in range(max_tries):
            cap = cv2.VideoCapture(i)
            if not cap.read()[0]:
                cap.release()
                continue
            else:
                available_cameras.append(i)
                cap.release()
        
        if available_cameras:
            camera_list = "\n".join([f"摄像头 {i}" for i in available_cameras])
            messagebox.showinfo("可用摄像头", f"检测到以下摄像头设备:\n{camera_list}")
        else:
            messagebox.showinfo("摄像头检测", "未检测到可用摄像头设备")
    
    def select_file(self):
        """打开文件选择对话框"""
        file_path = filedialog.askopenfilename(
            title="选择视频文件",
            filetypes=[("视频文件", "*.mp4 *.avi *.mkv *.mov *.flv"), ("所有文件", "*.*")]
        )
        
        if file_path:
            self.file_path_entry.delete(0, tk.END)
            self.file_path_entry.insert(0, file_path)
            self.status_var.set("加载文件: " + self.file_path_entry.get())
    
    def build_arguments(self):
        args = []
        
        # 处理输入参数
        input_type = self.input_type.get()
        if input_type == "device":
            input_value = self.input_device.get()
            if input_value:
                args.extend(["--input", input_value])
        elif input_type == "file":
            input_value = self.file_path_entry.get()
            if input_value:
                args.extend(["--input", input_value])
        elif input_type == "screen":
            try:
                x = int(self.screen_x.get())
                y = int(self.screen_y.get())
                width = int(self.screen_width.get())
                height = int(self.screen_height.get())
                args.extend(["--input", str(x), str(y), str(width), str(height)])
            except ValueError:
                messagebox.showerror("输入错误", "屏幕坐标和尺寸必须为整数")
                return None
        
        # 处理可选参数 - 为需要值的参数添加占位值 "1"
        if self.draw_landmarks.get():
            args.extend(["--landmarks", "1"])
        
        if self.draw_bpm.get():
            args.extend(["--bpm", "1"])
        
        if self.flip_output.get():
            args.extend(["--flip", "1"])
        
        if self.record_output.get():
            args.extend(["--record", "1"])
        
        # TTL参数
        ttl = self.ttl_value.get()
        if ttl.isdigit():
            args.extend(["--ttl", ttl])
        else:
            messagebox.showerror("输入错误", "TTL必须是整数")
            return None
        
        # 次要设备参数
        secondary = self.secondary_device.get()
        if secondary:
            args.extend(["--second", secondary])
        
        return args
    
    def load_config(self):
        """从配置文件加载设置"""
        config = configparser.ConfigParser()
        
        try:
            if os.path.exists(self.config_file):
                config.read(self.config_file)
                
                if 'Settings' in config:
                    settings = config['Settings']
                    
                    # 加载输入设置
                    self.input_type.set(settings.get('input_type', 'device'))
                    self.input_device.delete(0, tk.END)
                    self.input_device.insert(0, settings.get('input_device', '0'))
                    
                    # 加载文件路径
                    self.file_path_entry.delete(0, tk.END)
                    self.file_path_entry.insert(0, settings.get('file_path', ''))
                    
                    # 加载屏幕设置
                    self.screen_x.delete(0, tk.END)
                    self.screen_x.insert(0, settings.get('screen_x', '0'))
                    self.screen_y.delete(0, tk.END)
                    self.screen_y.insert(0, settings.get('screen_y', '0'))
                    self.screen_width.delete(0, tk.END)
                    self.screen_width.insert(0, settings.get('screen_width', '0'))
                    self.screen_height.delete(0, tk.END)
                    self.screen_height.insert(0, settings.get('screen_height', '0'))
                    
                    # 加载选项设置
                    self.draw_landmarks.set(settings.getboolean('draw_landmarks', False))
                    self.draw_bpm.set(settings.getboolean('draw_bpm', False))
                    self.flip_output.set(settings.getboolean('flip_output', False))
                    self.record_output.set(settings.getboolean('record_output', False))
                    
                    # 加载TTL设置
                    self.ttl_value.delete(0, tk.END)
                    self.ttl_value.insert(0, settings.get('ttl_value', '30'))
                    
                    # 加载次要设备设置
                    self.secondary_device.delete(0, tk.END)
                    self.secondary_device.insert(0, settings.get('secondary_device', ''))
                    
                    self.status_var.set("配置已加载")
                    return True
        except Exception as e:
            messagebox.showerror("加载配置失败", f"无法加载配置文件: {str(e)}")
        
        self.status_var.set("使用默认配置")
        return False
    
    def save_config(self):
        """保存当前设置到配置文件（不保存input_device中的文件路径）"""
        config = configparser.ConfigParser()
        config['Settings'] = {}
        settings = config['Settings']
        
        # 保存输入设置
        settings['input_type'] = self.input_type.get()
        settings['input_device'] = self.input_device.get()  # 保存摄像头序号
        settings['file_path'] = "" # self.file_path_entry.get()  不保存文件路径
        
        # 保存屏幕设置
        settings['screen_x'] = self.screen_x.get()
        settings['screen_y'] = self.screen_y.get()
        settings['screen_width'] = self.screen_width.get()
        settings['screen_height'] = self.screen_height.get()
        
        # 保存选项设置
        settings['draw_landmarks'] = str(self.draw_landmarks.get())
        settings['draw_bpm'] = str(self.draw_bpm.get())
        settings['flip_output'] = str(self.flip_output.get())
        settings['record_output'] = str(self.record_output.get())
        
        # 保存TTL设置
        settings['ttl_value'] = self.ttl_value.get()
        
        # 保存次要设备设置
        settings['secondary_device'] = self.secondary_device.get()
        
        try:
            with open(self.config_file, 'w', encoding='utf-8') as configfile:
                config.write(configfile)
            return True
        except Exception as e:
            messagebox.showerror("保存配置失败", f"无法保存配置文件: {str(e)}")
            return False
    
    def on_closing(self):
        """窗口关闭时保存配置，终止运行的进程并退出"""
        # 终止当前运行的进程
        if self.current_process and self.current_process.poll() is None:
            try:
                self.current_process.terminate()
                self.current_process.wait(timeout=2)  # 等待2秒让进程结束
                if self.current_process.poll() is None:
                    self.current_process.kill()  # 如果进程仍在运行，强制终止
                self.status_var.set("已终止运行的应用")
            except Exception as e:
                messagebox.showerror("终止进程失败", f"无法终止运行的应用: {str(e)}")
        
        # 保存配置
        if self.save_config():
            self.status_var.set(f"配置已保存到 {self.config_file}")
        
        self.root.destroy()
    
    def launch_app_with_save(self):
        """保存配置后启动应用"""
        if self.save_config():
            self.status_var.set(f"配置已保存到 {self.config_file}")
            self.launch_app()
    
    def launch_app(self):
        # 构建命令行参数
        cmd_args = self.build_arguments()
        if cmd_args is None:
            return
        
        # 终止当前运行的进程（如果有）
        if self.current_process and self.current_process.poll() is None:
            try:
                self.current_process.terminate()
                self.current_process.wait(timeout=2)
                if self.current_process.poll() is None:
                    self.current_process.kill()
                self.status_var.set("已终止之前运行的应用")
            except Exception as e:
                messagebox.showerror("终止进程失败", f"无法终止之前运行的应用: {str(e)}")
        
        # 获取当前脚本目录
        script_dir = os.path.dirname(os.path.abspath(__file__))
        
        # 主程序是当前目录下的main.py
        main_script = os.path.join(script_dir, "main.py")
        
        # 构建完整命令
        subprocess.Popen ([sys.executable, os.path.join(script_dir, "log.py")])
        command = [sys.executable, main_script] + cmd_args

        try:
            self.status_var.set("正在启动应用...")
            # 启动子进程并保存引用
            self.current_process = subprocess.Popen(command)
            
            # 应用启动后更新状态
            self.status_var.set(f"应用已启动 (进程ID: {self.current_process.pid})")
            
        except Exception as e:
            messagebox.showerror("启动错误", f"无法启动应用: {str(e)}")
            self.status_var.set("启动失败")

if __name__ == "__main__":
    root = tk.Tk()
    app = VideoAppLauncher(root)
    root.mainloop()